#include <avr/io.h>
#include <util/delay.h>

#include "gao.h"

#define LED_PORT           PORTD
#define LED_DDR            DDRD
#define LED_PIN            5

#define GAO_TX_PORT       PORTB
#define GAO_TX_DDR        DDRB
#define GAO_TX_PIN        7

#define GAO_TX_RETRIES    5
#define GAO_MSG_SIZE      24

#define GAO_HIGH          (GAO_TX_PORT |=  (1 << GAO_TX_PIN))
#define GAO_LOW           (GAO_TX_PORT &= ~(1 << GAO_TX_PIN))

#define GAO_SWITCH_DELAY  _delay_ms(0.590)

unsigned char GAO_CMD_PAIR[GAO_MSG_SIZE] = {0x00,0x00,0x01,0x01,0x01,0x00,0x00,0x00,0x01,0x01,0x00,0x00,0x01,0x01,0x00,0x00,0x01,0x00,0x00,0x01,0x01,0x00,0x01,0x00};
unsigned char GAO_CMD_ON[GAO_MSG_SIZE]   = {0x00,0x00,0x01,0x01,0x01,0x00,0x00,0x00,0x01,0x01,0x00,0x00,0x01,0x01,0x00,0x00,0x01,0x00,0x00,0x01,0x01,0x01,0x01,0x01};
unsigned char GAO_CMD_OFF[GAO_MSG_SIZE]  = {0x00,0x00,0x01,0x01,0x01,0x00,0x00,0x00,0x01,0x01,0x00,0x00,0x01,0x01,0x00,0x00,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x00};



void gao_init()
{
    GAO_TX_DDR |= (1 << GAO_TX_PIN);
    LED_DDR |= (1 << LED_PIN);
    LED_PORT |= (1 << LED_PIN);
}

void gao_pair()
{
    gao_send_cmd(GAO_CMD_PAIR);
}

void gao_on()
{
    gao_send_cmd(GAO_CMD_ON);
}

void gao_off()
{
    gao_send_cmd(GAO_CMD_OFF);
}



void gao_send_cmd(unsigned char* cmd)
{
    for (unsigned char i = 0; i < GAO_TX_RETRIES; ++i)
    {
        // GAO start pattern
        for (unsigned char i = 0; i < 4; ++i)
        {
            shortShort();
        }
    
        // GAO data
        for (unsigned char i = 0; i < GAO_MSG_SIZE; ++i)
        {
            if (cmd[i] == 0x00)
            {
                shortShort();
                shortLong();
            }
            else
            {
                shortLong();
                shortShort();
            }
        }

        // GAO stop pattern
        GAO_HIGH;
        _delay_ms(0.295); // Half of a switch delay
        GAO_LOW;
        
        // GAO burst delay
        _delay_ms(7);
    }
}

void shortShort()
{
    GAO_HIGH;
    GAO_SWITCH_DELAY;
    GAO_LOW;
    GAO_SWITCH_DELAY;
}

void shortLong()
{
    GAO_HIGH;
    GAO_SWITCH_DELAY;
    GAO_LOW;
    GAO_SWITCH_DELAY;
    GAO_SWITCH_DELAY;
}
